import stream from 'stream';

import { Context } from 'koa';

import type { ResponseCode } from '../types';

export const RESPONSE_MAP = {
  100: 'Continue',
  101: 'Switching Protocols',
  102: 'Processing',
  200: 'OK',
  201: 'Created',
  202: 'Accepted',
  203: 'Non-Authoritative Information',
  204: 'No Content',
  205: 'Reset Content',
  206: 'Partial Content',
  207: 'Multi-Status',
  208: 'Already Reported',
  226: 'IM Used',
  300: 'Multiple Choices',
  301: 'Moved Permanently',
  302: 'Found',
  303: 'See Other',
  304: 'Not Modified',
  305: 'Use Proxy',
  306: 'Switch Proxy',
  307: 'Temporary Redirect',
  308: 'Permanent Redirect',
  400: 'Bad Request',
  401: 'Unauthorized',
  402: 'Payment Required',
  403: 'Forbidden',
  404: 'Not Found',
  405: 'Method Not Allowed',
  406: 'Not Acceptable',
  407: 'Proxy Authentication Required',
  408: 'Request Timeout',
  409: 'Conflict',
  410: 'Gone',
  411: 'Length Required',
  412: 'Precondition Failed',
  413: 'Payload Too Large',
  414: 'URI Too Long',
  415: 'Unsupported Media Type',
  416: 'Range Not Satisfiable',
  417: 'Expectation Failed',
  421: 'Misdirected Request',
  422: 'Unprocessable Entity',
  423: 'Locked',
  424: 'Failed Dependency',
  426: 'Upgrade Required',
  428: 'Precondition Required',
  429: 'Too Many Requests',
  431: 'Request Header Fields Too Large',
  451: 'Unavailable For Legal Reasons',
  500: 'Internal Server Error',
  501: 'Not Implemented',
  502: 'Bad Gateway',
  503: 'Service Unavailable',
  504: 'Gateway Timeout',
  505: 'HTTP Version Not Supported',
  506: 'Variant Also Negotiates',
  507: 'Insufficient Storage',
  508: 'Loop Detected',
  510: 'Not Extended',
  511: 'Network Authentication Required',
};

/**
 * 格式化响应类，用于统一格式化后端返回的HTTP响应
 */
export class Resp {
  /**
   * 成功响应方法，该方法执行通常直接return，避免进入响应处理中间件
   * @param ctx 上下文对象，包含响应的相关信息和方法
   * @param data 可选参数，包含响应的数据
   * @param msg 可选参数，自定义响应消息
   * 说明：该方法用于格式化HTTP成功响应，设置状态码为200，并组织相应的响应体
   */
  static success<T = any>(ctx: Context, data?: T, msg?: string) {
    ctx.status = 200;
    ctx.type = 'json';
    ctx.body = {
      code: 200,
      success: true,
      message: msg || RESPONSE_MAP[200],
      result: data,
    };
  }

  /**
   * 通用响应方法，用于传递数据和自定义消息到响应处理中间件，后不需要return
   * @param ctx 上下文对象，包含响应的相关信息和方法
   * @param data 可选参数，包含响应的数据
   * @param message 可选参数，自定义响应消息
   * @param code 可选参数，自定义响应码，默认为200
   * 说明：该方法用于格式化一个包含数据和自定义消息的响应，适用于多种响应场景
   */
  static transfer<T = any>(ctx: Context, data?: T, message?: string, code?: ResponseCode) {
    ctx.type = 'json';
    ctx.code = code || 200;
    ctx.msg = message;
    ctx.body = data;
  }

  /**
   * 客户端错误响应方法，不要轻易使用clientError，使用了之后是走responseHandler中间件，这意味着错误信息不会被记录到日志中
   * @param ctx 上下文对象，包含响应的相关信息和方法
   * @param message 可选参数，自定义错误消息
   * @param code 可选参数，自定义错误码，默认为400
   * 说明：该方法用于格式化客户端错误响应，设置状态码为400，并组织相应的错误信息
   */
  static clientError(ctx: Context, message?: string, code?: ResponseCode) {
    ctx.type = 'json';
    ctx.code = code || 400;
    ctx.msg = message;
  }

  /**
   * 服务端错误响应方法，不要轻易使用serverError，使用了之后是走responseHandler中间件，这意味着错误信息不会被记录到日志中
   * @param ctx 上下文对象，包含响应的相关信息和方法
   * @param message 可选参数，自定义错误消息
   * @param code 可选参数，自定义错误码，默认为500
   * 说明：该方法用于格式化服务端错误响应，设置状态码为500，并组织相应的错误信息
   */
  static serverError(ctx: Context, message?: string, code?: ResponseCode) {
    ctx.type = 'json';
    ctx.code = code || 500;
    ctx.msg = message;
  }

  /**
   * 渲染模板
   * @param ctx 上下文对象，包含响应的相关信息和方法
   * @param file 模板文件名
   * @param content 模板内容
   */
  static template(ctx: Context, file: string, content: Record<string, any>) {
    ctx.type = 'html';
    return ctx.render(file, content);
  }

  /**
   * 能够被直接访问的文件，通常为流式的图片头像
   * @param ctx
   * @param file
   * @param type
   */
  static notAuthFile(ctx: Context, file: stream, type: string) {
    ctx.isOriginal = true;
    ctx.type = type;
    ctx.body = file;
  }
}
